﻿using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Security;
using System.Threading;
using PM.Entities;

namespace PM.BusinessLayer
{
    /***************************************************
     * Клас забезпечує безпеку при роботі з додатком
     * *************************************************/
    public static class AppSecurityContext
    {
        /************************************************************************************
         * властивість повертає адрес по замовчуванню.                                                  *
         * Якщо користувач авторизовний, то на сторінку для авторизованих користувачів,     *
         * якщо ні, то на сторінку із запитом для вводу пари Логін та Пароль                *
         * **********************************************************************************/
        public static string DefaultUrl
        {
            get { return IsAuthenticated ? GetDefaultUrl() : FormsAuthentication.LoginUrl; }
        }
        
        //повертає адрес по замовчуванню
        static private string GetDefaultUrl()
        {
            return "~/Default.aspx";
        }

        /*********************************************************
         * Об'єкт, що зберігає дані про авторизованого користувача
         * Клас описаний в PM.Entities.AuthentificatedUserInfo
         * *****************************************************************/
        public static AuthentificatedUserInfo AuthenticatedUser
        {
            get{return (AuthentificatedUserInfo)HttpContext.Current.Items["UserInfo"];}
            private set{HttpContext.Current.Items["UserInfo"] = value;}
        }

        //властивість повертає логічне значення, що відповідає тому чи користувач авторизований
        public static bool IsAuthenticated
        {
            get { return HttpContext.Current.Items["UserInfo"] != null; }
        }

        //Метод який проводить авторизацію та аутентифікацію користувача в системі
        public static void Login(string userName, string password)
        {
            User user = (new UserController()).Login(userName, password);
            AuthenticatedUser = new AuthentificatedUserInfo(user);
            string userID = user.UserID.ToString();
            
            /*****************************************************************
             * Метод забезпечує аутентифікацію на основі ролей.
             * Задає поточного користувача потоку (для безпеки основи ролей)
             * ***************************************************************/
            HttpContext.Current.User = Thread.CurrentPrincipal =
                new GenericPrincipal(new GenericIdentity(userID), GetUserRoles(user.UserID));
            
            //якщо ми намагалися зайти на сторінку, яка потребує авторизації
            //і нас перенаправив сервер на сторінку для залогінення,
            //то цей адрес запамятовуємо і повернемось назад
            string redirectUrl = HttpContext.Current.Request["ReturnUrl"];
            
            if (string.IsNullOrEmpty(redirectUrl))
            {
                redirectUrl = DefaultUrl; 
            }

            //В масив Cookie записуємо деяку інформацію про користувача,
            //а саме його ідентифікатор. Другий параметр служить для опції "Запам'ятати мене"
            FormsAuthentication.SetAuthCookie(userID, false);
            
            //Перенеправляємо користувача на сторінку по замовчуванню
            HttpContext.Current.Response.Redirect(redirectUrl);
        }

        /*******************************************************
         * Метод служить для "виходу" (очищення всіх записів з браузера про користувача)
         * ********************************************************/
        public static void Logout()
        {
            AuthenticatedUser = null;
            HttpContext.Current.User = Thread.CurrentPrincipal = null;
            FormsAuthentication.SignOut();
            HttpContext.Current.Response.Redirect(FormsAuthentication.LoginUrl);
        }

        /*****************************************************************
         * метод оновлює дані про користувача. при його роботі з додатком.
         * перевстановлює дату останньої дії з додатком.
         * ***************************************************************/
        public static void RefreshUser()
        {
            if (HttpContext.Current.User == null || !HttpContext.Current.User.Identity.IsAuthenticated)
            {
                AuthenticatedUser = null;
                HttpContext.Current.User = Thread.CurrentPrincipal = null;
                return;
            }
            int userId = int.Parse(HttpContext.Current.User.Identity.Name);
            User user = new UserController().GetUser(userId);
            AuthenticatedUser = new AuthentificatedUserInfo(user);
            HttpContext.Current.User = Thread.CurrentPrincipal =
                    new GenericPrincipal(new GenericIdentity(user.UserID.ToString()), GetUserRoles(userId));
        }

        /**************************************************************
         * Метод повертає масив з назвами ролей для забезпечення 
         * ************************************************************/
        private static string[] GetUserRoles(int userID)
        {
            return new UserController().GetUserInRoles(userID).Select(r => r.Role.Name).ToArray();
        }
    }
}
